#include "Preduce.h"
#include "NEON_2_SSE.h"
//neon优化，适用于飞腾派
Mat Preduce::repeat_neon(Mat &A){
    Mat B(A.size(),CV_8UC1);
    Mat C(A.size(),CV_8UC1);
    Mat R;
    vector<Mat> channels;
    for(int row = 0; row < A.size().height; row++){
        for(int col = 0; col < A.size().width; col+=16){
            int8x16_t vec1 = vld1q_u8(&A.at<uchar>(row,col));
            
            vst1q_u8(&B.at<uchar>(row,col),vec1);
            vst1q_u8(&C.at<uchar>(row,col),vec1);
        }
    }
    channels.push_back(A);
    channels.push_back(B);
    channels.push_back(C);
    merge(channels,R);
    return R;
}

// Ycrcb空间，Otsu算法识别肤色
Mat Preduce::YCbCr_Otsu(Mat &frame){
    Mat frameYCrCb,RIOresult,RIOframe;
    cvtColor(frame, frameYCrCb , COLOR_BGR2YCrCb);
    vector<Mat> channels;
    split(frameYCrCb, channels);
    RIOresult = channels[1];
    threshold(RIOresult, RIOresult, 0, 255, THRESH_BINARY | THRESH_OTSU);
    frame.copyTo(RIOframe, RIOresult);
    return RIOframe;
}


// 预处理主体
Mat Preduce::Pre(Mat &input){
    //使用LIME算法进行光照矫正
    input = lime.run(input);
    input.convertTo(input,CV_8UC3);

    //肤色获取 去除背景
    Mat out1 = YCbCr_Otsu(input);

    cvtColor(out1, out1 , COLOR_BGR2GRAY);

    //滤波 二值化
    medianBlur(out1,out1,15);
    GaussianBlur(out1,out1,Size(9,9),1,1);
    threshold(out1, out1, 0, 255, THRESH_BINARY);

    //绘制轮廓
    Mat ones = Mat::ones(3,3,CV_8UC1);
    cv::morphologyEx(out1,out1, MORPH_OPEN,ones); //开运算
    std::vector<std::vector<Point>> contours;
    cv::findContours(out1, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    //获取周长最大的轮廓
    Mat one = Mat::ones(out1.rows,out1.cols,CV_8UC1);
    double max = 0;
    int idx;
    for(int i = 0 ;i < contours.size();i++){
        double s = arcLength(contours[i],true);
        if(s >= max){
            max = s;
            idx = i;
        }else{
            max = max;
            idx = idx;
        }
    }
    drawContours(one,contours,idx,255,3);
    //通道转换，用于yolo输入
    // Mat channelss[3];
    // channelss[0] = one;
    // channelss[1] = one;
    // channelss[2] = one;
    Mat out2 = repeat_neon(one);
    // Mat out2;
    // merge(channelss,3,out2);
    bitwise_not(out2,out2); //反色
    return out2;
}